package com.querie.controller;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Map.Entry;
import java.util.Iterator;

import org.apache.mahout.cf.taste.common.NoSuchItemException;
import org.apache.mahout.cf.taste.common.NoSuchUserException;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.recommender.svd.ALSWRFactorizer;
import org.apache.mahout.cf.taste.impl.recommender.svd.Factorization;
import org.apache.mahout.math.DenseVector;
import org.apache.mahout.math.Vector;

import com.querie.config.Configuration;

public class ModelGenerationController {
    static double lambda = 0.9;
	static final String dirName = Configuration.getTestInputDir();
	static int numOfFolds = Configuration.getNumOfFolds(); 
	static int numOfIterations = Configuration.getNumOfIterations();
	static int numOfFeatures = Configuration.getNumOfFeatures();
	static private BufferedWriter mfout;

	public static void buildModel() {
		try {
			System.out.println("Building matrix factorization model for each fold");

			for (int index = 1; index <= numOfFolds; index++)
			{
				System.out.println("Processing for fold "+index);
				FileDataModel model = new FileDataModel(new File(dirName+"/fold"+index+"/training.dat"));
				mfout = new BufferedWriter(new OutputStreamWriter(
						new FileOutputStream(dirName+"/fold"+index+"/mf.dat")));
				ALSWRFactorizer factorizer;
				Factorization factorization;

				factorizer = new ALSWRFactorizer(model, numOfFeatures, lambda,
						numOfIterations);
				factorization = factorizer.factorize();

				Iterable<Entry<Long, Integer>> itemFeatureMappings = factorization
						.getItemIDMappings();
				Iterable<Entry<Long, Integer>> userFeatureMappings = factorization
						.getUserIDMappings();

				double predictedRating = 0.0;
				long userId = 0l;
				long itemId = 0l;

				Iterator<Entry<Long, Integer>> userIterator = userFeatureMappings
						.iterator();

				while (userIterator.hasNext()) {
					Iterator<Entry<Long, Integer>> itemIterator = itemFeatureMappings
							.iterator();
					userId = userIterator.next().getKey();

					while (itemIterator.hasNext()) {
						itemId = itemIterator.next().getKey();
						Vector U = null;
						Vector M = null;
						try {
							U = new DenseVector(
									factorization.getUserFeatures(userId));
							M = new DenseVector(
									factorization.getItemFeatures(itemId));
							predictedRating = U.dot(M);
							mfout.write(userId + "," + itemId + ","
									+ predictedRating);
//							System.out.println(userId + "," + itemId + ","
//									+ predictedRating);
							mfout.newLine();
							mfout.flush();

						} catch (NoSuchUserException e) {
							e.printStackTrace();
						} catch (NoSuchItemException e) {
							e.printStackTrace();
						}
					}
				}
			}
			System.out.println("Matrix factorization model generation completed.");

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TasteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// public static double calculateRMSE(Factorization factorization) {
	// double result = 0;
	// String line = new String();
	//
	// try {
	// BufferedReader br = new BufferedReader(
	// new InputStreamReader(new FileInputStream(new File(
	// "c:\\dataset\\1000X10\\ratings_probe_1000X10.csv"))));
	// RunningAverage average = new FullRunningAverage();
	// while ((line = br.readLine()) != null) {
	// StringTokenizer strToken = new StringTokenizer(line, ",");
	//
	// int userId = Integer.parseInt(strToken.nextToken());
	// int itemId = Integer.parseInt(strToken.nextToken());
	// double ratings = Double.parseDouble(strToken.nextToken());
	// Vector U = null;
	// Vector M = null;
	// try {
	// U = new DenseVector(factorization.getUserFeatures(userId));
	// M = new DenseVector(factorization.getItemFeatures(itemId));
	// } catch (NoSuchUserException e) {
	// // TODO Auto-generated catch block
	// continue;
	// } catch (NoSuchItemException e) {
	// // TODO Auto-generated catch block
	// continue;
	// }
	// double predictedRating = U.dot(M);
	// // System.out.println("Predicted Rating = "+predictedRating+
	// // " Rating  = "+ ratings);
	// double err = ratings - predictedRating;
	// average.addDatum(err * err);
	// }
	//
	// result = Math.sqrt(average.getAverage());
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// return result;
	// }

	public static void main(String a[]) {
		new ModelGenerationController().buildModel();
	}
}
